home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Turnbull China Bikeride
/
Turnbull China Bikeride - Disc 1.iso
/
ARGONET
/
PD
/
GRAPHICS
/
GIF2RPC.SPK
/
source
/
s
/
map16_accura
next >
Wrap
Text File
|
1995-10-02
|
7KB
|
206 lines
; map16_accurate.s
; MACHINE: RISC OS
; LANGUAGE: OBJASM assembler
; AUTHOR: Cy Booker, cy@cheepnis.demon.co.uk
; LICENSE: FreeWare, Copyright (c) Cy Booker 1995
; PURPOSE: Given an arbitary 48-bit colour, what is the closest 16-bit colour?
GET OS:Hdr.os
;
; in middle we have |intensity-difference| <-- 0xffff * 2 / 0x1f
; so |i|^2 < 0x0110c631
; and so |d|^2 < 0x03325293
;
; the weights we want are:
; Red * 0.212671 *256 = 54 (0x36) *179 = 38 0x26
; Green * 0.715160 *256 = 183 (0xb7) *179 = 128 0x80
; Blue * 0.072169 *256 = 19 (0x13) *179 = 13 0x0d
;
; note we will use the *179 because it makes the inline multiplies very quick
; note we divide by 4 so that total difference fits in 32 (unsigned) bits
; ie (0x03325293 * 179 / 4) < 2^32
;
MACRO
Dump
[ {FALSE}
STMFD sp!, {a1-v6, ip, lr}
STMFD sp!, {d}
MOV a4, delta_grn
MOV a3, delta_blu
MOV a2, delta_red
ADR a1, __format
IMPORT _printf
; BL _printf
B %FT1
_format = "delta= {%8x, %8x, %8x}, dist= %8x\n", 0
ALIGN
1
ADD sp, sp, #4
LDMFD sp!, {a1-v6, ip, lr}
]
MEND
EXPORT map_scaled_rgb_to_16bpp_colour_accurate
AREA |ARM$$code|, CODE, READONLY
ROUT
;
; In R0 -> structure, or NULL
; R1 = red nominally [0, 0xffff], but clipped as necessary
; R2 = green nominally [0, 0xffff], but clipped as necessary
; R3 = blue nominally [0, 0xffff], but clipped as necessary
; Out R0 = 16 bit colour number (%0bbb bbgg gggr rrrr)
; structure[0] = error in approximating red intensity
; structure[1] = error in approximating green intensity
; structure[2] = error in approximating blue intensity
;
ROUT
str RN a1
orig_red RN a2
orig_grn RN a3
orig_blu RN a4 ; implicit
delta_red RN v1 ;\;
delta_grn RN v2 ; \;
delta_blu RN v3 ;-->
scaled_red RN v4 ;\;
scaled_grn RN v5 ; \;
scaled_blu RN v6 ;-->
t RN ip
delta RN str
d RN scaled_red
dmin RN scaled_blu
^ 0, sp
L_str # 4 ; all structure offsets are implicit!
L_best_delta # 4 * 3
L_scaled_red # 4
L_scaled_grn # 0 ; this is in a register!
L_scaled_blu # 4
L_distance_red # 4 ; need to remember this
sizeof_L * :INDEX: {VAR}
map_scaled_rgb_to_16bpp_colour_accurate
STMFD sp!, {v1-v6, lr}
STR str, [sp, #-sizeof_L]! ; store and reserve stack space
MOV lr, #0xff00
ORR lr, lr, #0xff
CMP orig_red, #0x10000 ; ensure in range [0, 0xffff]
MOVHS orig_red, #0
MOVGE orig_red, lr
CMP orig_grn, #0x10000
MOVHS orig_grn, #0
MOVGE orig_grn, lr
CMP orig_blu, #0x10000
MOVHS orig_blu, #0
MOVGE orig_blu, lr
AND t, orig_red, #&f800 ; t = simple approximation of red * 2 ^ (16 - 5)
ORR t, t, t, LSR #5
ORR t, t, t, LSR #10
ORR t, t, t, LSR #15 ; t ~= t * 0xffff / 0x1f
STR t, L_scaled_red
AND t, orig_grn, #&f800
ORR t, t, t, LSR #5
ORR t, t, t, LSR #10
ORR scaled_grn, t, t, LSR #15
AND t, orig_blu, #&f800
ORR t, t, t, LSR #5
ORR t, t, t, LSR #10
ORR t, t, t, LSR #15
STR t, L_scaled_blu
MOV delta, #&0800
ORR delta, delta, #&0042 ; delta= 0xffff / 0x1f
MOV dmin, #&ffffffff
MOV delta_red, delta
red_loop
LDR t, L_scaled_red
ADD t, t, delta_red
CMP t, #0x10000
BHS skip_red_loop ; ensure in range [0, 0xffff]
SUBS d, t, orig_red
RSBMI d, d, #0 ; makes multiply faster
MULNE t, d, d
; scale for red...
ADDNE d, t, t, LSR #1 ; |r|^2 * 0.072169 * 179 / 4 = |r|^2 * 0x06
ADDNE d, d, t, LSL #3 ; |r|^2 * 0.072169 * 179 / 4 = |r|^2 * 0x26
STR d, L_distance_red
MOV delta_blu, delta
blu_loop
LDR t, L_scaled_blu
ADD t, t, delta_blu
CMP t, #0x10000
BHS skip_blu_loop ; ensure in range [0, 0xffff]
SUBS t, t, orig_blu
RSBMI t, t, #0
MULNE lr, t, t
; scale for blue
ADDNE d, d, lr ; (|b|^2 / 4) * 0x04
ADDNE d, d, lr, LSR #2 ; (|b|^2 / 4) * 0x05
ADDNE d, d, lr, LSL #1 ; (|b|^2 / 4) * 0x0d
MOV delta_grn, delta
grn_loop
ADD t, scaled_grn, delta_grn
CMP t, #0x10000
BHS skip_grn_loop ; ensure in range [0, 0xffff]
SUBS t, t, orig_grn
RSBMI t, t, #0 ; speeds up multiplication
MUL lr, t, t
; scale for green ...
ADD d, d, lr, LSL #5 ; |g|^2 * 0.715160 * 179 / 4 = |g|^2 * 0x80
Dump
CMP d, dmin
MOVLO dmin, d
STMLOIB sp, {delta_red, delta_grn, delta_blu} ; note the best so far
SUB d, d, lr, LSL #5 ; restore distance accumulator
skip_grn_loop
SUBS delta_grn, delta_grn, delta
BLS grn_loop ; loop +1, 0, -1
LDR d, L_distance_red ; restore distance accumulator
skip_blu_loop
SUBS delta_blu, delta_blu, delta
BLS blu_loop ; loop +1, 0, -1
skip_red_loop
SUBS delta_red, delta_red, delta
BLS red_loop ; loop +1, 0, -1
; the final lr is just to clear the stack
LDMIA sp!, {str, delta_red, delta_grn, delta_blu, scaled_red, scaled_blu, lr}
ADD scaled_red, scaled_red, delta_red
ADD scaled_grn, scaled_grn, delta_grn
ADD scaled_blu, scaled_blu, delta_blu
TEQ str, #0
SUBNE orig_red, orig_red, scaled_red
SUBNE orig_grn, orig_grn, scaled_grn
SUBNE orig_blu, orig_blu, scaled_blu
STMNEIA str, {orig_red, orig_grn, orig_blu} ; store `error'
MOV t, scaled_red, LSR #16 - 5
MOV lr, scaled_grn, LSR #16 - 5
ORR t, t, lr, LSL #5
MOV lr, scaled_blu, LSR #16 - 5
ORR a1, t, lr, LSL #10 ; construct 16-bit colour number
LDMFD sp!, {v1-v6, pc}^
END